package bootstrap

import (
	"context"
	"gitee.com/lipore/go-nio/pkg/channel"
	"gitee.com/lipore/go-nio/pkg/reactor"
	"gitee.com/lipore/go-nio/pkg/transport"
	"net/url"
)

type Bootstrap interface {
	Context() context.Context
	Listen(address string) (reactor.Reactor, error)
	Shutdown()
}

type bootstrap struct {
	ctx         context.Context
	cancel      context.CancelFunc
	tsFactories transport.Factories
	reactors    []reactor.Reactor
	cgs         channel.Groups
}

func New(options ...Option) Bootstrap {
	o := NewOptions(options...)
	ctx, cancel := context.WithCancel(context.Background())
	return &bootstrap{
		ctx:         ctx,
		cancel:      cancel,
		tsFactories: o.tsFactories,
		reactors:    make([]reactor.Reactor, 0),
		cgs:         o.cgs,
	}
}

func (b *bootstrap) Context() context.Context {
	return b.ctx
}

func (b *bootstrap) Listen(address string) (reactor.Reactor, error) {
	u, err := url.Parse(address)
	if err != nil {
		return nil, err
	}
	acceptor, err := b.tsFactories.Listen(u)
	if err != nil {
		return nil, err
	}
	r := reactor.NewReactor(b.ctx, acceptor)
	for _, cg := range b.cgs {
		r.AddChannelGroup(cg)
	}
	b.reactors = append(b.reactors, r)
	return r, nil
}

func (b *bootstrap) Shutdown() {
	for _, r := range b.reactors {
		_ = r.Close()
	}
	b.cancel()
}
